package org.lijma.demo.siteplan.main;

import org.lijma.demo.siteplan.config.LoadFailedException;
import org.lijma.demo.siteplan.config.RouteInfo;
import org.lijma.demo.siteplan.config.RoutesLoader;
import org.lijma.demo.siteplan.config.impl.FileRoutesLoader;
import org.lijma.demo.siteplan.core.MatchedRoute;
import org.lijma.demo.siteplan.core.StopManager;
import org.lijma.demo.siteplan.core.StopSearcher;
import org.lijma.demo.siteplan.core.impl.ManagerImpl;
import org.lijma.demo.siteplan.main.impl.CaseRunnerImpl;

import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

public class Main {

    private static Logger LOG = Logger.getLogger(Main.class.getName());
    private static final int ERROR_EXIT_CODE = -1;
    private static final int SUCCESS_EXIT_CODE = 0;

    public static void main(String[] args){

        RoutesLoader loader = new FileRoutesLoader();
        List<RouteInfo> routeInfos = null;
        try {
            routeInfos = loader.loadRouteInfo();
        } catch (LoadFailedException e) {
            LOG.severe("load routes error happened, shutting down the Main");
            System.exit(ERROR_EXIT_CODE);
        }
        if(routeInfos == null || routeInfos.size()==0){
            LOG.warning("no any routes configured, shutting down the Main");
            System.exit(SUCCESS_EXIT_CODE);
        }

        //StopManager is constructing the whole Stop and Routes information
        final ManagerImpl manager = new ManagerImpl();
        StopManager stopManager = manager;
        for(RouteInfo ri : routeInfos){
            stopManager.addRoute(ri.getStartStopName(),ri.getEndStopName(),ri.getWeight());
        }
        LOG.finest("system established successfully, and it is ready for search now");


        // verify result as mail mentioned
        final StopSearcher searcher = manager;
        CaseRunner runner = new CaseRunnerImpl();

        runner.runCase(1, new CaseRunner.Case() {
            public int invoke() throws Exception {
                return searcher.findDistanceOfRoutes(Arrays.asList("A","B","C"));
            }
        });

        runner.runCase(2, new CaseRunner.Case() {
            public int invoke() throws Exception {
                return searcher.findDistanceOfRoutes(Arrays.asList("A","D"));
            }
        });

        runner.runCase(3, new CaseRunner.Case() {
            public int invoke() throws Exception {
                return searcher.findDistanceOfRoutes(Arrays.asList("A","D","C"));
            }
        });

        runner.runCase(4, new CaseRunner.Case() {
            public int invoke() throws Exception {
                return searcher.findDistanceOfRoutes(Arrays.asList("A","E","B","C","D"));
            }
        });

        runner.runCase(5, new CaseRunner.Case() {
            public int invoke() throws Exception {
                return searcher.findDistanceOfRoutes(Arrays.asList("A","E","D"));
            }
        });

        runner.runCase(6, new CaseRunner.Case() {
            public int invoke() throws Exception {
                List list = searcher.getTripsByMaximumSteps("C","C",3);
                return list.size();
            }
        });

        runner.runCase(7, new CaseRunner.Case() {
            public int invoke() throws Exception {
                List list = searcher.getTripsByRequiredStops("A","C",4);
                return list.size();
            }
        });

        runner.runCase(8, new CaseRunner.Case() {
            public int invoke() throws Exception {
                MatchedRoute matchedRoute = searcher.getShortestRouteAndDistance("A","C");
                return matchedRoute.getTotalWeight();
            }
        });

        runner.runCase(9, new CaseRunner.Case() {
            public int invoke() throws Exception {
                MatchedRoute matchedRoute = searcher.getShortestRouteAndDistance("B","B");
                return matchedRoute.getTotalWeight();
            }
        });

        runner.runCase(10, new CaseRunner.Case() {
            public int invoke() throws Exception {
                List<MatchedRoute> list = searcher.getMatchedRouteAndDistance("C","C",30);
                return list.size();
            }
        });

    }

}
